import java.net.*;
import java.io.*;
import java.util.*;
import SMUVE.*;
import static SMUVE.Debug.*;

public class SMUVE_Server {

	ServerSocket listenSocket;
	Socket connection;

	DataManager data_manager;

//	Vector<Room> rooms = new Vector<Room>();
//	Vector<Player> players = new Vector<Player>();
	Vector<Server_Thread> threads = new Vector<Server_Thread>();
//	Vector<Item> items = new Vector<Item>();

	String hostname;
	int client_port;
	int update_port;
	String conffile = "SMUVE_Server.config";

	Update_Manager update_manager;
	static final String delimiter = SMUVE.Msg_Pipe.delimiter;

	public SMUVE_Server() {
		hostname = "";
		client_port = 8901;
		update_port = 8902;
	}

	public void set_client_port(int p) {
		client_port = p;
	}

	public void set_update_port(int p) {
		update_port = p;
	}

	/* Item methods */
/*
	public boolean put_down_item(String player, String item_name) {
		boolean retval = false;
		Item item = get_item(item_name);
		if (item != null) {
			if (item.get_location().equals(player)) {
				item.put_down(get_current_room(player));
				retval = true;
			}
		}

		return(retval);
	}

	public boolean pick_up_item(String player, String item_name) {
		boolean retval = false;
		Item item = get_item(item_name);
		if (item != null) {
			if (item.get_location().equals(get_current_room(player))) {
				item.pick_up(player);
				retval = true;
			}
		}

		return(retval);
	}

	public String get_room_items(String room) {
		String item_list = "";
		for (int i = 0; i < items.size(); i++) {
			if (items.get(i).get_location().equals(room)) {
				if (i > 0) {
					item_list += delimiter;
				}
				item_list += items.get(i).get_name();
			}
		}

		return(item_list);
	}

	public String get_player_items(String player) {
		String item_list = "";
		for (int i = 0; i < items.size(); i++) {
			if (items.get(i).get_location().equals(player)) {
				if (i > 0) {
					item_list += delimiter;
				}
				item_list += items.get(i).get_name();
			}
		}

		return(item_list);
	}

	private boolean add_item(Item item) {
		Item i = get_item(item.get_name());
		boolean retval = false;

		if (i == null) {
			Room room = data_manager.get_room(item.get_location());

			if (room != null) {
				retval = items.add(item);
			}
		}

		return(retval);
	}

	private Item get_item(String name) {
		Item item = null;

		for (int i = 0; i < items.size(); i++) {
			if (items.get(i).get_name().equals(name)) {
				item = items.get(i);
				break;
			}
		}
	
		return(item);
	}
*/

	private boolean login(String player, String password) {
		boolean retval = false;
		Player p = data_manager.get_player(player);

		if (p != null) {
			/* XXX: kludge to allow muliple logins for server and admin */
			if (p.get_name().equals("server") || p.get_name().equals("admin"))
				p.set_active(false);

			retval = (p.get_password().equals(password) && !p.get_active());
		}
		else {
			p = new Player(player, "Den", password);
			retval = add_player(p);
		}

		if (retval) {
			if (!player.equals("server")) {
				p.set_active(true);
			}
		}

		return(retval);
	}	
	
	private boolean adminLogin(String admin, String password) {
		//boolean retval = false;
		//Player p = data_manager.get_player(admin);
		//debug(p.get_name());
		//if (p != null) {
			if (admin.equals("admin"))
			{
				//debug(p.get_password());
				//debug(password);
			return(password.equals("admin_pass"));
			}	
		//}
		return false;
	}

	private boolean logout(String player) {
		boolean retval = false;
		Player p = data_manager.get_player(player);

		if (p != null) {
			p.set_active(false);
			retval = true;
		}

		return(retval);
	}
	
	public boolean add_room(Room room) {
		//boolean retval = rooms.add(room);
		boolean retval = data_manager.add_room(room);
		return(retval);
	}

	public boolean remove_player(Player player) {
		Player p = data_manager.get_player(player.get_name());
		boolean retval = false;

		if (p.get_password().equals(player.get_password())) {
			retval = data_manager.remove_player(p);
		}

		return(retval);
	}

	public boolean add_player(Player player) {
		Player p = data_manager.get_player(player.get_name());
		boolean retval = false;

		if (p == null ) {
			retval = data_manager.add_player(player);
		}

		return(retval);
	}


	public String get_current_room(String player) {
		String retval = "";
		Player p = data_manager.get_player(player);
		if (p != null) {
			retval = p.get_room();
		}

		return(retval);
	}

/*
	public Player get_player(String player) {
		Player player = null;

		for (int i = 0; i < players.size(); i++) {
			if (players.get(i).get_name().equals(player)) {
				player = players.get(i);
				break;
			}
		}

		return(player);
	}
*/
			
	private boolean is_local_move(String player, String room) {
		boolean retval = false;

		Room r = data_manager.get_room(get_current_room(player));
		Player p = data_manager.get_player(player);

		debug("r = " + r);
		debug("p = " + p);
		debug("portal_exists(" + r.get_name() + ", " + room + ") returned " +
			data_manager.portal_exists(r.get_name(), room));

		
		if (r != null && p != null && data_manager.portal_exists(r.get_name(), room)) {
			Portal portal = r.get_portal(room);
			debug("portal.server = " + portal.get_server());
			debug("portal.client_port = " + portal.get_client_port());
			debug("portal.update_port = " + portal.get_update_port());
			debug("hostname = " + hostname);
			debug("client_port = " + client_port);
			debug("update_port = " + update_port);
			if (portal.get_server().equals(hostname) &&
					portal.get_client_port() == client_port &&
					portal.get_update_port() == update_port) {
				retval = true;
			}
		}

		debug("is_local_move(" + player + ", " + room + ") returned " + retval);
		return(retval);
	}

	public boolean move(String player, String room) {
		boolean retval = false;

		Room r = data_manager.get_room(get_current_room(player));
		Player p = data_manager.get_player(player);

		/* Don't allow a player to move to a room that isn't connected
		 * to their current room.
		 */
		if (data_manager.portal_exists(r.get_name(), room)) {
			Portal portal = r.get_portal(room);
			if (portal.get_server().equals(hostname) &&
					portal.get_client_port() == client_port &&
					portal.get_update_port() == update_port) {
				p.set_room(room);
				debug("handled local move");
				retval = true;
			}
			else {
				try {
					Socket sock = new Socket(portal.get_server(),
						portal.get_client_port());
					Msg_Pipe pipe = new Msg_Pipe(sock);
					if (!pipe.login("server", "server_pass"))
						return(false);

					p.set_room(room);
					p.set_active(false);
					pipe.add_player(p);
					Vector<Item> moved_items = new Vector<Item>();

					Item[] items = data_manager.get_player_items(p.get_name());
					for (int i = 0; i < items.length; i++) {
						if (pipe.add_item(items[i]))
							moved_items.add(items[i]);
						else {
							/* Don't allow items to be moved to a remote server
							 * that already has an item with the same name. Instead
							 * strip the item from the player and put it back in the
							 * room.  XXX: the item could be kept locally for the user
							 * in case they return.
							 */
							items[i].set_location(r.get_name());
							items[i].set_in_room(true);
							debug("cannot move " + items[i].get_name() + " to remote server");
						}
					}
					
					for (int i = 0; i < items.length; i++) {
						if (moved_items.contains(items[i])) {
							data_manager.remove_item(items[i]);
						}
					}

					moved_items.clear();

					pipe.logout(player); // make sure the player will be able to move
					pipe.close();
					sock.close();
					debug("handled remote move");
					retval = true;
				}
				catch (UnknownHostException e) {
					retval = false;
				}
				catch (IOException e) {
					retval = false;
				}
			}
		}
		else
			debug("got invalid portal to move through");
		
		return(retval);
	}

	/* XXX: replaced by DataManager.get_room() */
/*
	public Room get_room(String room) {
		Room r = null;

		for (int i = 0; i < rooms.size(); i++) {
			if (rooms.get(i).get_name().equals(room)) {
				r = rooms.get(i);
				break;
			}
		}

		return(r);
	}
*/

	/* XXX: replaced by DataManager.room_exists() */
/*
	public boolean room_exists(String room) {
		return(data_manager.room_exists(room));
		boolean retval = false;

		for (int i = 0; i < rooms.size(); i++) {
			if (rooms.get(i).get_name().equals(room)) {
				retval = true;
				break;
			}
		}

		return(retval);
	}

	public String get_room_players(String room) {
		String resp = "";
		int count = 0;
		for (int i = 0; i < players.size(); i++) {
			Player p = players.get(i);
			if (p.get_room().equals(room) && p.get_active()) {
				// add delimiter after the first player name 
				if (count++ != 0)
					resp += delimiter;

				resp += p.get_name();
			}
		}

		return(resp);
	}

	public Player get_player(String name) {
		Player p = null;

		for (int i = 0; i < players.size(); i++) {
			if (players.get(i).get_name().equals(name)) {
				p = players.get(i);
				break;
			}
		}

		return(p);
	}
*/

	public void runServer() {
		String message;
		boolean done = false;

		/* add the server-to-server user info */
		//players.add(new Player("server", "", "server_pass"));
		//JATdata_manager.add_player(new Player("server", "", "server_pass"));


/*
		r.add_portal(new Portal("Zoo", hostname, client_port, update_port));
		r2.add_portal(new Portal("Den", hostname, client_port, update_port));
*/
					
		try {
			listenSocket = new ServerSocket(client_port);
			System.out.print("Server started");

			try {
				InetAddress here = InetAddress.getLocalHost();
				hostname = here.getHostName();
				System.out.println(" on " + hostname + ", port " + client_port);
			} catch (UnknownHostException e) {
				System.out.println("Problem with local host\n");
			}

			/* create the DataManager to maintain the server's state */
			data_manager = new DataManager(hostname, client_port, update_port);
			data_manager.load_state();

			/* Start a thread that listens for client connections from
			 * clients wishing to receive updates.
			 */
			update_manager = new Update_Manager();
			update_manager.start();

			//JATdata_manager.add_room(new Room("Den", "The Den"));
			//JATdata_manager.add_room(new Room("Zoo", "Where the wild things are"));
			//rooms.add(new Room("Den", "The Den"));
			//rooms.add(new Room("Zoo", "Where the wild things are"));
			//JATdata_manager.add_player(new Player("Norm", "Den", "pass"));
			//players.add(new Player("Norm", "Den", "pass"));
			Room r = data_manager.get_room("Den");
			Room r2 = data_manager.get_room("Zoo");
			//JATdata_manager.add_portal("Den", new Portal("Zoo", hostname, client_port, update_port), false);

			while (!done) {
				connection = listenSocket.accept();
				System.out.println("Connection request received");
				Server_Thread thd = new Server_Thread(connection);
				thd.start();
				threads.add(thd);
				Thread.sleep(100);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			System.out.println("Exception");
		}
		finally {
			System.out.println("Shutting down Server");
			for (int i = 0; i < threads.size(); i++) {
				threads.get(i).interrupt();
			}
		}
	}

	public class InputThread extends Thread {
		boolean done = false;
		boolean ready;

		Msg_Pipe pipe;
		private static final String delimiter = Msg_Pipe.delimiter;

		public InputThread (Msg_Pipe pipe)
		{
			this.pipe = pipe;
			ready = false;
		}

		public void run() {
			try {
				/* Here is where messages from the client are processed */
				/* XXX: this needs to be thought through more thouroughly.
				 * Should messages received be translated into function calls?
				 */
				//pipe.send_message("server_ready");
				int save_count = 0;
				while (pipe != null && !done) {
					int count = pipe.available();
					//debug("count = " + count);
					if (count > 0) {
						String msg = pipe.recv_message();
						String type = Msg_Pipe.get_message_type(msg);
						String body = Msg_Pipe.get_message_body(msg);
						debug("Got message: " + msg);
						save_count++;
						if (type.equals("shutdown")) {
							done = true;
							update_manager.update_notify("", "shutdown" + delimiter + "server is shutting down");
							Thread.sleep(5000);
							data_manager.save_state();
							System.exit(0);
						}
						else if (type.equals("chat") || type.equals("chat_player")) {
							String[] result = pipe.parse_message(body);
							String resp = pipe.failure;
							if (result.length == 3) {
								String player = result[0];
								String to_player = result[1];
								String message = result[2];
							
								update_manager.update_notify(to_player, "chat" +
									delimiter + player + delimiter + "[private] " +
									message);
								update_manager.update_notify(player, "chat" +
									delimiter + to_player + delimiter + "[private] " +
									message);
								resp = pipe.success;
							}
							pipe.send_message(resp);
						}
						else if (type.equals("chat_room")) {
							String[] result = pipe.parse_message(body);
							String resp = pipe.failure;
							if (result.length == 3) {
								String player = result[0];
								String to_room = result[1];
								String message = result[2];

								Player[] players = data_manager.get_room_players(to_room);
								for (int i = 0; i < players.length; i++) {
									update_manager.update_notify(players[i].get_name(),
										"chat" + delimiter + player + delimiter
										+ message);
								}
								resp = pipe.success;
							}
							pipe.send_message(resp);
						}
						else if (type.equals("login")) {
							String resp = pipe.failure;
							String[] result = pipe.parse_message(body);
							if (result.length == 2) {
								String player = result[0];
								String pass = result[1];
								if (login(player, pass)) {
									resp = pipe.success;
									String room = get_current_room(player);
									update_manager.update_notify("", "player_arrived" +
										delimiter + room + delimiter + player);
								}
							}
							pipe.send_message(resp);
						}
						else if (type.equals("admin_login")) {
							String resp = pipe.failure;
							String[] result = pipe.parse_message(body);
							if (result.length == 2) {
								String player = result[0];
								String pass = result[1];
								debug("at admin check");
								if (adminLogin(player, pass)) {
								resp=pipe.success;
								}
							}
							pipe.send_message(resp);
						}
						else if (type.equals("logout")) {
							String resp = pipe.failure;
							String player = body;

							if (logout(player)){
								resp = pipe.success;	
								String room = get_current_room(player);
								update_manager.update_notify("", "player_departed" +
										delimiter + room + delimiter + player);
							}
							pipe.send_message(resp);
						}
						else if (type.equals("add_room")) {
							String resp = pipe.failure;
							String update_msg = "";
							String[] result = pipe.parse_message(body);
							if (result.length == 2) {
								Room room = new Room(result[0], result[1]);

								if (add_room(room)) {
									resp = pipe.success;
									update_msg = "room_added" + delimiter +
										room.get_name() + delimiter +
										room.get_description();
								}
							}

							pipe.send_message(resp);
							if (resp.equals(pipe.success)) {
								update_manager.update_notify("", update_msg);
							}
						}
						else if (type.equals("add_portal")) {
							String resp = pipe.failure;
							String update_msg = "";
							String[] result = pipe.parse_message(body);
							for (int i = 0; i < result.length; i++)
								debug("result[" + i + "] " + result[i]);

							if (result.length == 6) {
								String room = result[0];
								String to_room = result[1];
								String server = result[2];
								int cport = Integer.parseInt(result[3]);
								int uport = Integer.parseInt(result[4]);
								boolean add_local = Boolean.parseBoolean(result[5]);
								if (data_manager.add_portal(room, new Portal(to_room, server, cport, uport), add_local)) {
									resp = pipe.success;
									update_msg = "add_portal" + delimiter + body;
								}
								else
									debug("add_portal failed: " + body);
							}

							pipe.send_message(resp);
							if (resp.equals(pipe.success))
								update_manager.update_notify("", update_msg);
						}
						else if (type.equals("get_portals")) {
							String resp = "";
							if (data_manager.room_exists(body)) {
								Room r = data_manager.get_room(body);
								String[] p = r.get_portals();
								String plist = "";
								if (p != null && p.length > 0) {
									for (int i = 0; i < p.length; i++) {
										if (i > 0)
											plist += delimiter;
											plist += p[i];
									}
								}
								resp = pipe.success + delimiter + plist;
							}
							else
								resp = pipe.failure;
							pipe.send_message(resp);
						}
						else if (type.equals("get_server")) {
							String resp = pipe.success + delimiter + hostname +
								delimiter + client_port + delimiter + update_port;
							pipe.send_message(resp);
						}
						else if (type.equals("add_player")) {
							String[] result = pipe.parse_message(body);
							String resp = pipe.failure;
							String update_msg = "";

							if (result.length == 3) {
								String name = result[0];
								String room = result[1];
								String password = result[2];

								Player player = new Player(name, room, password);
								if (add_player(player)) {
									resp = pipe.success;
									update_msg = "player_added" + delimiter + name +
										delimiter + room;
								}
							}

							pipe.send_message(resp);

							if (resp.equals(pipe.success))
								update_manager.update_notify("", update_msg);
						}
						else if (type.equals("add_item")) {
							String[] result = pipe.parse_message(body);
							String resp = pipe.failure;
							if (result.length == 3) {
								String name = result[0];
								String room = result[1];
								String desc = result[2];

								Item item = new Item(name, room, desc, true);
								if (data_manager.add_item(item))
									resp = pipe.success;
							}
							pipe.send_message(resp);
							if (resp.equals(pipe.success))
								//roddy change to item_added?
								update_manager.update_notify("", "add_item" +
									delimiter + body);
						}
						else if (type.equals("get_room_items")) {
							String location = body;
							String resp = pipe.failure;
							Room room = data_manager.get_room(location);
							if (room != null) {
								Item[] result = data_manager.get_room_items(room.get_name());
								resp = pipe.success + delimiter;
								for (int i = 0; i < result.length; i++) {
									if (i != 0)
										resp += delimiter;
									resp += result[i].get_name();
								}
							}
							pipe.send_message(resp);
						}
						else if (type.equals("get_player_items")) {
							String location = body;
							Player player = data_manager.get_player(location);
							String resp = pipe.failure;
							if (player != null) {
								Item[] result = data_manager.get_player_items(player.get_name());
								resp = pipe.success + delimiter;
								debug("get_player_items found " + result.length + " items");
								for (int i = 0; i < result.length; i++) {
									if (i != 0)
										resp += delimiter;
									resp += result[i].get_name();
								}
							}
							pipe.send_message(resp);
						}
						else if (type.equals("get_item")) {
							String item = body;
							String resp = pipe.failure;
							Item i = null;
							if ((i = data_manager.get_item(item)) != null) {
								resp = pipe.success + delimiter + i.get_name() +
									delimiter + i.get_location() + delimiter +
									i.get_description();
							}
							pipe.send_message(resp);
						}
						else if (type.equals("is_item_locked")) {
							String item = body;
							String resp = pipe.failure;
							Item i = null;
							if ((i = data_manager.get_item(item)) != null) {
								resp = pipe.success + delimiter + i.is_locked();
							}
							pipe.send_message(resp);
						}
						else if (type.equals("put_down_item")) {
							String resp = pipe.failure;
							boolean retval = false;
							String[] result = pipe.parse_message(body);
							if (result.length == 2) {
								String player = result[0];
								String item = result[1];
								if (data_manager.put_down_item(player, item)) {
									resp = pipe.success;
									String room = get_current_room(player);
									update_manager.update_notify("", "item_arrived" +
										delimiter + room + delimiter + item + delimiter +
										player);
								}
							}
							pipe.send_message(resp);
						}
						else if (type.equals("pick_up_item")) {
							String resp = pipe.failure;
							boolean retval = false;
							String[] result = pipe.parse_message(body);
							if (result.length == 2) {
								String player = result[0];
								String item = result[1];
								if (data_manager.pick_up_item(player, item)) {
										resp = pipe.success;
										String room = get_current_room(player);
										update_manager.update_notify("", "item_gone" +
											delimiter + room + delimiter + item +
											delimiter + player);
								}
							}
							pipe.send_message(resp);
						}
						else if (type.equals("move")) {
							String[] result = pipe.parse_message(body);
							if (result.length != 2)
								throw(new InvalidMessageException("Invalid move message"));
							String room = result[1];
							String player = result[0];
							Room r = data_manager.get_room(get_current_room(player));
							Portal p = r.get_portal(room);

							Boolean local_move = is_local_move(player, room);

							if (move(player, room)) {
								pipe.send_message(pipe.success);
								String update_msg = "";

								if (local_move) {
									update_manager.update_notify("", "player_arrived" +
										delimiter + room + delimiter + player);
									update_manager.update_notify("", "player_departed" +
										delimiter + r.get_name() + delimiter + player);
								}
								else {
									debug("logging user out");
									logout(player);
									debug("removing user");
									remove_player(data_manager.get_player(player));
									// Here is where one print stack comes out
									update_manager.update_notify(player, "reconnect" +
										delimiter + p.get_server() + delimiter +
										p.get_client_port() + delimiter +
										p.get_update_port());
									update_manager.remove_subscriber(player);
									debug("sent reconnect message");
									done = true; // exit the thread
									update_manager.update_notify("", "player_departed" +
										delimiter + r.get_name() + delimiter + player);
								}
							}
							else
								pipe.send_message(pipe.failure);
						}
						else if (type.equals("get_players")) {
							Player[] result = data_manager.get_players();
							String resp = pipe.success + pipe.delimiter;
							for (int i = 0; i < result.length; i++) {
								if (i != 0)
									resp += delimiter;
								resp += result[i].get_name();
							}
							pipe.send_message(resp);
						}
						else if (type.equals("get_room_players")) {
							String resp = "";
							if (data_manager.room_exists(body)) {
								Player[] result = data_manager.get_room_players(body);
								resp += pipe.success + delimiter;

								for (int i = 0; i < result.length; i++) {
									if (i != 0)
										resp += delimiter;
									resp += result[i].get_name();
								}
							}
							else
								resp += pipe.failure;

							pipe.send_message(resp);
						}
						else if (type.equals("get_current_room")) {
							String room = get_current_room(body);
							if (!room.equals("")) {
								pipe.send_message(pipe.success + 
									delimiter + room);
							}
							else
								pipe.send_message(pipe.failure);
						}
						else if (type.equals("get_rooms")) {
							Room[] result = data_manager.get_rooms();
							String resp = pipe.success + delimiter;
							for (int i = 0; i < result.length; i++) {
								if (i != 0)
									resp += delimiter;
								resp += result[i].get_name();
							}
							pipe.send_message(resp);
						}
						else if (type.equals("get_player")) {
							Player p;
							if ((p = data_manager.get_player(body)) != null)
								pipe.send_message(pipe.success + delimiter + p);
							else
								pipe.send_message(pipe.failure);
						}
						//Roddy, still testing
						else if (type.equals("lock_item")) {
							String resp = pipe.failure;
							boolean retval = false;
							String[] result = pipe.parse_message(body);
							if (result.length == 1) {
								String i=result[0];
								Item item=data_manager.get_item(i);
								if (data_manager.lock_item(item)) {
										resp = pipe.success;
										update_manager.update_notify("", "item_locked" +
											delimiter + item.get_location() + delimiter + i);
								}
							}
							pipe.send_message(resp);
						}
						else if (type.equals("unlock_item")) {
							String resp = pipe.failure;
							boolean retval = false;
							String[] result = pipe.parse_message(body);
							if (result.length == 1) {
								String i=result[0];
								Item item=data_manager.get_item(i);
								if (item!=null && data_manager.unlock_item(item)) {
										String location=
										resp = pipe.success;
										update_manager.update_notify("", "item_unlocked" +
											delimiter + item.get_location() + delimiter + i);
								}
							}
							pipe.send_message(resp);
						}
						else if (type.equals("get_room")) {
							Room r;
							if ((r = data_manager.get_room(body)) != null)
								pipe.send_message(pipe.success + delimiter + r);
							else
								pipe.send_message(pipe.failure);
						}
						else if (type.equals("get_items")) {
							Item[] result = data_manager.get_items();
							String resp = pipe.success + delimiter;
							for (int i = 0; i < result.length; i++) {
								if (i != 0)
									resp += delimiter;
								resp += result[i].get_name();
							}
							pipe.send_message(resp);
						}
						else if (type.equals("remove_player")) {
							String[] result = pipe.parse_message(body);
							String resp = pipe.failure;
							String update_msg = "";

							if (result.length == 1) {
								String name = result[0];
								Player player=data_manager.get_player(name);
								if (player!=null&&remove_player(player)) {
									String room=player.get_room();
									Item[] item_list=data_manager.get_player_items(name);
									for(int i=0; i<item_list.length; i++)
									{
										if(data_manager.put_down_item(player, item_list[i]))
										update_manager.update_notify("", "item_arrived" +
												delimiter + room + delimiter + item_list[i].get_name());
									}
									resp = pipe.success;
									update_msg = "player_removed" + delimiter + room +
										delimiter + name;
								}
							}

							pipe.send_message(resp);

							if (resp.equals(pipe.success))
								update_manager.update_notify("", update_msg);
						}
						else if (type.equals("remove_item")) {
							String[] result = pipe.parse_message(body);
							String resp = pipe.failure;
							String update_msg = "";
							boolean held=false;
							String location="";
							if (result.length == 1) {
								String name = result[0];
								Item item=data_manager.get_item(name);
								if (item!=null&&data_manager.remove_item(item)) {
									//not sure if this will still work, but I think it should
									location=item.get_location();
									held=item.held();
									resp = pipe.success;
									//do we need to make this the actual room? what happens when on a player?
									update_msg = "item_removed" + delimiter + location +
										delimiter + name;
								}
							}

							pipe.send_message(resp);

							if (resp.equals(pipe.success)){
								if(held)
								update_manager.update_notify(location, update_msg);
								else
								update_manager.update_notify("", update_msg);
							}
						}
						//not pretty. For server portals, will ultimately result in a failure response
						else if (type.equals("remove_portal")) {
							String[] result = pipe.parse_message(body);
							String resp = pipe.failure;
							String update_msg = "";

							if (result.length == 2) {
								String room = result[0];
								String to_room= result[1];
								Room r=data_manager.get_room(room);
								if(r!=null&&data_manager.remove_portal(r, to_room))
								{
									resp=pipe.success;
									update_msg="portal_removed"+delimiter+room+delimiter+to_room;
								}
							}

							pipe.send_message(resp);

							if (resp.equals(pipe.success))
								update_manager.update_notify("", update_msg);
						}
						//this definitely needs some thought and work. What happens to players and items in room?
						else if (type.equals("remove_room")) {
							String[] result = pipe.parse_message(body);
							String resp = pipe.failure;
							String update_msg = "";

							if (result.length == 1) {
								String name = result[0];
								Room room=data_manager.get_room(name);
								boolean player_in_room=false;
								//check for players in room
								if(room!=null) {
									Player[] players=data_manager.get_players();
									for(int i=0; i<players.length; i++)
									{
										if(players[i].get_room().equals(room.get_name()))
											player_in_room=true;
									}
									if (!player_in_room && data_manager.remove_room(room)) {
										//all items in room removed
										Item[] room_items=data_manager.get_room_items(name);
										for(int i=0; i<room_items.length; i++)
										{
											if(data_manager.remove_item(room_items[i]))
											update_manager.update_notify("", "item_removed" +
													delimiter + name + delimiter + room_items[i].get_name());
										}
										//all portals to other rooms must be removed
										//do once remove_portal figured out
										Portal[] room_portals=room.getPortals();
										//for loop
										for(int i=0; i<room_portals.length; i++)
										{
											if(data_manager.remove_portal(room, room_portals[i].get_room()))
												update_manager.update_notify("", "portal_removed" +
														delimiter + name + delimiter + room_portals[i].get_room());
										}
										resp = pipe.success;
										update_msg = "room_removed" + delimiter + name;
									}
								}
							}

							pipe.send_message(resp);

							if (resp.equals(pipe.success))
								update_manager.update_notify("", update_msg);
						}
						else if (type.equals("modify_item")) {
							String[] result = pipe.parse_message(body);
							String resp = pipe.failure;
							String update_msg = "";
							boolean held=false;
							String location="";
							if (result.length == 3) {
								String name = result[0];
								String new_name=result[1];
								String new_description= result[2];
								Item item=data_manager.get_item(name);
								if (item!=null&&data_manager.modify_item(item, new_name, new_description)) {
									//not sure if this will still work, but I think it should
									location=item.get_location();
									held=item.held();
									resp = pipe.success;
									update_msg = "item_modified" + delimiter + item+ delimiter+ name;
								}
							}

							pipe.send_message(resp);
							//still need to update admin, so both notifications go out
							if (resp.equals(pipe.success)){
								if(held)
									update_manager.update_notify(location, update_msg);
									update_manager.update_notify("", update_msg);
							}
						}
						else if (type.equals("modify_room")) {
							String[] result = pipe.parse_message(body);
							String resp = pipe.failure;
							String update_msg = "";

							if (result.length == 3) {
								String name = result[0];
								String new_name=result[1];
								String new_description= result[2];
								Room room=data_manager.get_room(name);
								if (room!=null&&data_manager.modify_room(room, new_name, new_description)) {
									resp = pipe.success;
									//even though name and location are the same since it is a room
									update_msg = "room_modified" + delimiter + room + delimiter+ name;
								}
							}

							pipe.send_message(resp);

							if (resp.equals(pipe.success))
								update_manager.update_notify("", update_msg);
						}
						else if (type.equals("modify_player")) {
							String[] result = pipe.parse_message(body);
							String resp = pipe.failure;
							String update_msg = "";

							if (result.length == 2) {
								String name = result[0];
								String new_name=result[1];
								Player player=data_manager.get_player(name);
								if (player!=null&&data_manager.modify_player(player, new_name)) {
									//not sure if this will still work, but I think it should
									resp = pipe.success;
									update_msg = "player_modified" + delimiter + player+ delimiter+ name;
								}
							}

							pipe.send_message(resp);

							if (resp.equals(pipe.success))
								update_manager.update_notify("", update_msg);
						}
						else {
							debug("Unknown message type: " + type);
							pipe.send_message(pipe.failure + pipe.delimiter +
									"unknown message type: '"+ type + "'");
						}
					}
					Thread.sleep(100);
					if (save_count > 10) {
						data_manager.save_state();
						save_count = 0;
					}
				}

				//in.close();
				pipe.close();
			}
			catch (EOFException e) {
			}
			catch (IOException e) {
			}
			catch (InterruptedException e) {
				System.out.println("Thread Interrupted");
			}
			catch (Exception e) {
				System.out.println("Caught Exception");
				e.printStackTrace();
			}
		}
	}

	private class Subscriber {
		private String player;
		private Msg_Pipe pipe;

		public Subscriber(String player, Msg_Pipe pipe) {
			this.player = player;
			this.pipe = pipe;
		}

		public String get_player() {
			return(player);
		}

		public void notify(String msg) {
			pipe.send_message(msg);
		}
	}

	public class Update_Manager extends Thread {
		ServerSocket update_socket;
		Vector<Subscriber> subscribers = new Vector<Subscriber>();

		public void run() {
			try {
				update_socket = new ServerSocket(update_port);
				debug("Update_Manager started on port " + update_port);
				while (true) {
					connection = update_socket.accept();
					debug("got update connection");
					Msg_Pipe pipe = new Msg_Pipe(connection);
					debug("waiting for player");
					String player = pipe.recv_message();
					subscribers.add(new Subscriber(player, pipe));

					Thread.sleep(100);
				}
			}
			catch (InterruptedException e) {
				System.out.println("Thread Interrupted");
			}
			catch (IOException e) {
				System.out.println("Update_Manager.run: caught IOException");
				e.printStackTrace();
			}
		}

		public void update_notify(String player, String msg) {
			for (int i = 0; i < subscribers.size(); i++) {
				Subscriber sub = subscribers.get(i);
				if (sub.get_player().equals(player) || player.equals(""))
					sub.notify(msg);
				//subscribers.get(i).update_notify(player, msg);
			}
		}

		public void remove_subscriber(String player) {
			for (int i = 0; i < subscribers.size(); i++) {
				Subscriber sub = subscribers.get(i);
				if (sub.get_player().equals(player)) {
					subscribers.remove(sub);
					break;
				}
			}
		}
	}

	public class Update_Thread extends Thread {
		Socket sock;
		Msg_Pipe update_pipe;
		String player;

		public Update_Thread(Socket connection) {
			sock = connection;

			try {
				update_pipe = new Msg_Pipe(sock);
				try {
					while (update_pipe.available() == 0) 
						Thread.sleep(100);
				}
				catch (InterruptedException e) {
				}

				player = update_pipe.recv_message();
			}
			catch (IOException e) {
				System.out.println("Update_Thread: caught IOException");
				e.printStackTrace();
			}
		}

		public String get_player() {
			return(player);
		}

		public void run() {
			try {
				/* loop forever */
				while (update_pipe != null)
					Thread.sleep(100);

				update_pipe.close();
			}
			catch (InterruptedException e) {
				System.out.println("Thread interrupted");
			}
			catch (Exception e) {
				System.out.println("Exception");
				e.printStackTrace();
			}
		}

		public void update_notify(String player, String msg) {
			try {
				if (player.equals("") || player.equals(this.player))
					update_pipe.send_message(msg);
			}
			catch (Exception e) {
				System.out.println("Exception");
			}
		}
	}

   public class Server_Thread extends Thread {
		Socket connection;
		Socket update_conn;
		Msg_Pipe pipe;

		public Server_Thread(Socket conn) throws Exception {
			connection = conn;
			pipe = new Msg_Pipe(connection);
		}

		public void run() {
			try {
				InputThread monitor = new InputThread(pipe);
				monitor.start();
				debug("monitor started");
			}
			catch (Exception e) {
				System.out.println("Exception");
			}
			
		}
	}

	public static void main(String [] args) {
		SMUVE_Server server = new SMUVE_Server();

		if (args.length > 0) {
			for (int i = 0; i < args.length; i++) {
				if (args[i].equals("-c")) {
					if (i + 1 < args.length)
						server.set_client_port(Integer.parseInt(args[i++ + 1]));
					else {
						System.out.println("missing client port argument");
						System.exit(1);
					}
				}
				else if (args[i].equals("-u")) {
					if (i + 1 < args.length)
						server.set_update_port(Integer.parseInt(args[i++ + 1]));
					else {
						System.out.println("missing client port argument");
						System.exit(1);
					}
				}
			}
		}

		server.runServer();
	}
}
